home *** CD-ROM | disk | FTP | other *** search
- /*
- * WICONCLOCK A utility that works with WICONIFY to display a
- * clock icon on every wIconify screen. The clock face
- * shows the current time, and updates as time passes.
- *
- * Copyright 1990 by Davide P. Cervone, all rights reserved.
- * You may use this code, provided this copyright notice is kept intact.
- */
-
-
- #define INTUITION_PREFERENCES_H /* don't need 'em */
- #include <intuition/intuitionbase.h>
- #include <devices/timer.h>
- #include <libraries/dos.h>
-
- #include "wIcon.h"
-
- static char *Program = "wIconClock v1.1";
- static char *Copyright =
- "Copyright (c) 1990 by Davide P. Cervone, all rights reserved";
-
-
- struct IntuitionBase *IntuitionBase;
- #define INTUITION_REV 0
-
- #define DELAYSECS 1 /* How often to look for time changes */
- #define DELAYMICS 0
-
- #define MAXSCREENS 24 /* Largest number of screens expected */
-
-
- #define STANDARD_TIME 1 /* 12 hour clock with AM/PM */
- #define MILITARY_TIME 2 /* 24 hour clock */
-
- #define EXIT_OK 0L
- #define EXIT_ERROR 10L
-
- #define REPORTFLAGS WI_REPORTOPEN| WI_REPORTCLOSE| WI_REPORTAUTOREMOVE
-
-
- /*
- * Clock face image size
- */
-
- #define CLOCKWIDTH 40
- #define CLOCKHEIGHT 19
- #define CLOCKDEPTH 2
- #define WORDSPERROW 3
-
-
- static struct timerequest TimerRequest; /* Timer IO request */
- static struct MsgPort *TimerPort; /* Timer IO reply port */
- static int TimerOpen; /* TRUE if timer open */
- static int TimerSet; /* TRUE if request pending */
- static int OldPri; /* Old process priority */
- static APTR ClockTask; /* Pointer to this task */
- static int TimeType = STANDARD_TIME; /* Time display type */
-
- /*
- * The clock face image data area
- */
- extern USHORT ClockData[CLOCKDEPTH][CLOCKHEIGHT*WORDSPERROW];
-
- /*
- * The clock icon name area
- */
- static char ClockName[] = "00:00 AM";
-
- /*
- * The clock icon's image structure
- */
- static struct Image ClockImage =
- {0,0, CLOCKWIDTH,CLOCKHEIGHT,CLOCKDEPTH, &ClockData[0][0], 0x03,0, NULL};
-
- /*
- * The clock icon definition
- */
- static WICON ClockIcon =
- {&ClockName[0], &ClockImage, NULL,NULL,
- 600,15, WI_AUTOREMOVE| WI_NOORGANIZE, REPORTFLAGS, NULL};
- static short ClockX,ClockY;
-
- static WICONREF *Clock[MAXSCREENS]; /* wIconRefs of all open clocks */
- static WICONREF *NewScreenClock; /* Clock receiving NEWSCREEN reports */
- static int ClockCount; /* How many are open */
-
-
- extern WICONREF *wAddIcon();
-
- /*
- * HandData tells how to draw each hand. Offset says how far to change
- * the x position from our current position, and count says how many
- * pixels in a row to use. {0,0} ends the list.
- */
- struct HandData {BYTE Offset,Count;};
-
- /*
- * The big hand has sixty positions, but these are brocken down into
- * four sets (15 minute chuncks) which are symmetric either by a
- * flip horizontally, vertically, or both.
- */
-
- static struct HandData BigHand[16][6] =
- {
- {{-1,2},{-1,2},{-1,2},{-2,4},{-2,4},{-1,2}},
- {{-1,2},{-1,2},{-1,3},{-1,3},{-1,3},{0,2}},
- {{-1,2},{-1,2},{-1,3},{-1,4},{0,3},{1,2}},
- {{-1,2},{-1,3},{0,3},{0,4},{1,3},{2,2}},
- {{-1,2},{0,2},{1,3},{1,4},{2,4},{4,1}},
- {{-1,2},{0,3},{1,4},{2,4},{4,3},{0,0}},
- {{-1,2},{0,3},{2,3},{3,4},{6,3},{0,0}},
- {{-1,2},{1,2},{3,3},{5,4},{7,3},{0,0}},
- {{-1,2},{1,3},{3,5},{6,4},{0,0},{0,0}},
- {{-1,3},{2,3},{4,4},{7,3},{0,0},{0,0}},
- {{-1,4},{2,4},{5,3},{8,2},{0,0},{0,0}},
- {{-1,5},{4,5},{7,5},{0,0},{0,0},{0,0}},
- {{-1,6},{3,7},{9,4},{0,0},{0,0},{0,0}},
- {{-1,5},{4,8},{0,0},{0,0},{0,0},{0,0}},
- {{-1,9},{8,5},{0,0},{0,0},{0,0},{0,0}},
- {{-1,14},{0,0},{0,0},{0,0},{0,0},{0,0}}
- };
-
-
- /*
- * The little hand has positions for each hour and half-hour, and
- * are brocken down in the same way as the big hand.
- */
-
- static struct HandData LittleHand[7][6] =
- {
- {{-1,2},{-1,2},{-2,4},{-1,2},{0,0},{0,0}},
- {{-1,2},{-1,3},{-1,3},{0,2},{0,0},{0,0}},
- {{-1,2},{0,3},{1,3},{2,2},{0,0},{0,0}},
- {{-1,3},{0,4},{2,3},{0,0},{0,0},{0,0}},
- {{-1,3},{1,4},{3,4},{0,0},{0,0},{0,0}},
- {{-1,5},{2,5},{0,0},{0,0},{0,0},{0,0}},
- {{-1,9},{0,0},{0,0},{0,0},{0,0},{0,0}}
- };
-
-
- /*
- * FreeClocks()
- *
- * For each clock in the clock array, remove the clock icon from the
- * screen, and clear its array position. Decrement the clock count as
- * we go.
- */
-
- static void FreeClocks()
- {
- short i;
-
- for (i=0; i<MAXSCREENS && ClockCount; i++)
- {
- if (Clock[i]) wRemoveIcon(Clock[i]);
- Clock[i] = NULL;
- ClockCount--;
- }
- }
-
-
- /*
- * Print()
- *
- * Find the standard AmigaDOS output file and write the output string
- * to the output file. This is intended as a substitute for printf()
- * when no formatting is required, and when you want a small executable.
- */
-
- static void Print(s)
- char *s;
- {
- ULONG OutFile;
- extern ULONG Output();
-
- OutFile = Output();
- if (OutFile && s) Write(OutFile,s,strlen(s));
- }
-
-
- /*
- * DoExit()
- *
- * Print an error message, if one is give, and set the return status.
- * Return the task priority to normal, and clean up any memory or
- * other resources that were allocated.
- * Exit with the correct return status.
- */
-
- static void DoExit(message)
- char *message;
- {
- int status = EXIT_OK;
-
- if (message)
- {
- Print(message);
- Print("\n");
- status = EXIT_ERROR;
- }
- SetTaskPri(ClockTask,OldPri);
- if (TimerSet) AbortIO(&(TimerRequest.tr_node));
- if (TimerOpen) CloseDevice(&TimerRequest);
- if (TimerPort) DeletePort(TimerPort);
- if (ClockCount) FreeClocks();
- if (ClockIcon.IconPort) DeletePort(ClockIcon.IconPort);
- if (IntuitionBase) CloseLibrary(IntuitionBase);
- _exit(status);
- }
-
- #define ISSPACE(x) (x == ' ' || x == '\t')
- #define NOTSPACE(x) (x != '\0' && x != ' ' && x != '\t')
-
-
- /*
- * ParseArgs()
- *
- * If there was a parameter line,
- * Skip the command (which is the first thing on the line).
- * Skip any trailing spaces.
- * Find the end-of-line and remove the new-line character and any
- * trailing blanks.
- * While there is more one the line
- * Find the first space (ie, the end of the word).
- * Mark the end of the word and skip any trailing spaces.
- * If the word is one of the time specifiers, save the type,
- * Otherwise, if the word is a position X,Y then save the position,
- * Otherwise exit with the usage message.
- * Continue looking at the rest of the line.
- */
-
- static void ParseArgs(line)
- char *line;
- {
- char *s;
- int X,Y;
-
- if (line)
- {
- while (ISSPACE(*line)) line++;
- while (NOTSPACE(*line)) line++;
- while (ISSPACE(*line)) line++;
- for (s = line; *s && *s != '\n'; s++);
- if (*s) *s = 0; if (s > line) while (*(--s) == ' ') *s = 0;
-
- while (*line)
- {
- s = line; while (NOTSPACE(*s)) s++;
- if (*s)
- {
- *s++ = 0;
- while (ISSPACE(*s)) s++;
- }
- if (stricmp(line,"MILITARY") == 0) TimeType = MILITARY_TIME; else
- if (stricmp(line,"STANDARD") == 0) TimeType = STANDARD_TIME; else
- if (sscanf(line,"%ld,%ld",&X,&Y) == 2)
- ClockX = X, ClockY = Y;
- else DoExit("Usage: wIconClock [MILITARY | STANDARD] [x,y]");
-
- line = s;
- }
- }
- }
-
-
- /*
- * CheckLibOpen()
- *
- * Call OpenLibrary() for the specified library, and check that the
- * open succeeded.
- */
-
- static void CheckLibOpen(lib,name,rev)
- APTR *lib;
- char *name;
- int rev;
- {
- extern APTR OpenLibrary();
-
- if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
- DoExit("Can't Open Library");
- }
-
-
- /*
- * SetupClock()
- *
- * Get a pointer to the clock task (the current task) and change the
- * task priority to 5 (so we update the screen a little faster).
- * Get a port for the clock icons, if possible.
- * Get a reply port for the timer requests, if possible.
- * Open the timer device, and initialize the timer request.
- */
-
- static void SetupClock()
- {
- extern struct MsgPort *CreatePort();
- extern APTR FindTask();
-
- ClockTask = FindTask(NULL);
- OldPri = SetTaskPri(ClockTask,5);
-
- ClockIcon.IconPort = CreatePort(0,0);
- if (ClockIcon.IconPort == NULL) DoExit("Can't Create Icon Port\n");
-
- TimerPort = CreatePort(0,0);
- if (TimerPort == NULL) DoExit("Can't Create Timer Port\n");
-
- if (OpenDevice(TIMERNAME,UNIT_VBLANK,&TimerRequest,0) != NULL)
- DoExit("Can't Open Timer Device");
- TimerRequest.tr_node.io_Message.mn_ReplyPort = TimerPort;
- TimerRequest.tr_node.io_Command = TR_ADDREQUEST;
- TimerRequest.tr_node.io_Flags = 0;
- TimerOpen = TRUE;
- }
-
-
- /*
- * UpdateTime()
- *
- * Set the time string to the proper characters for the specified
- * time display type. Trim the initial zero if the hour is only
- * one digit long.
- */
-
- static void UpdateTime(s,h,m)
- char s[];
- short h,m;
- {
- switch(TimeType)
- {
- case STANDARD_TIME:
- s[5] = ' ';
- s[6] = (h >= 12)? 'P': 'A';
- h = h % 12; if (h == 0) h = 12;
- break;
-
- case MILITARY_TIME:
- s[5] = 0;
- break;
- }
- s[0] = '0' + (h / 10);
- s[1] = '0' + (h % 10);
- s[2] = ':';
- s[3] = '0' + (m / 10);
- s[4] = '0' + (m % 10);
- if (s[0] == '0') s++;
- ClockIcon.Name = s;
- }
-
-
- /*
- * UpdateHand()
- *
- * dx and dy specify the direction we are moving on the clock face,
- * Hand is the hand array of the particular position we are using,
- * SetIt specifies whether we are adding or removing the hand.
- *
- * Start at the center of the clock.
- * For each {offset,count} pair,
- * Get the offset and count.
- * If there is anything to do,
- * Set the mask to the correct number of bits.
- * Shift the mask by the correct offset for the dx direction.
- * Divide the mask into three parts (one for each word in a row of
- * the clock image data).
- * If we are adding the had, clear those bits (to make the pen color 2)
- * Otherwise set them (to make the pen color 3).
- * Increment the y position in the correct direction.
- */
-
- static void UpdateHand(dx,dy,Hand,SetIt)
- short dx,dy;
- struct HandData *Hand;
- int SetIt;
- {
- short y = (CLOCKHEIGHT-1)/2 * WORDSPERROW;
- short i;
- ULONG mask;
- UWORD m1,m2,m3;
- short count,offset;
-
- for (i=0; i<6; i++)
- {
- count = Hand[i].Count;
- offset = Hand[i].Offset;
- if (count)
- {
- mask = ((1 << count) - 1);
- mask <<= (dx < 0)? (16 + offset): (16 - count - offset);
- m1 = mask >> (CLOCKWIDTH/2);
- m2 = (mask >> (16 - (32-(CLOCKWIDTH/2)))) & 0xFFFF;
- m3 = (mask << (32-(CLOCKWIDTH/2)) ) & 0xFFFF;
- if (SetIt)
- {
- ClockData[0][y] &= ~m1;
- ClockData[0][y+1] &= ~m2;
- ClockData[0][y+2] &= ~m3;
- } else {
- ClockData[0][y] |= m1;
- ClockData[0][y+1] |= m2;
- ClockData[0][y+2] |= m3;
- }
- }
- y += dy;
- }
- }
-
-
- /*
- * UpdateFace()
- *
- * Get the proper quadrant for the position of the big hand for the current
- * time, and update the big hand.
- * Now get the correct quadrant for the little hand:
- * shift the minutes by 15 mintes since we want the little hand to
- * change at a quarter after and a quarter of - that way the be one the
- * hour from a quarter of to a quarter after, and on the half hour from
- * a quarter after to a quarter to.
- * Take the hour modulo 12 and multiply by two (every other hand is the
- * hour position). If the minutes are in the half-hour range, increment
- * to the half-hour position.
- * Finally, reduce by quadrants, as before.
- * Update the clock face.
- */
-
- static void UpdateFace(h,m,SetIt)
- short h,m;
- int SetIt;
- {
- short dx,dy;
- short m1 = m;
-
- dx = 1; dy = -WORDSPERROW;
- if (m > 30) m -= 30, dx = -1, dy = WORDSPERROW;
- if (m > 15) m = 30 - m, dy = -dy;
- UpdateHand(dx,dy,&BigHand[m][0],SetIt);
-
- m1 += 15; if (m1 >= 60) m1 -= 60, h++;
- h %= 12; h *= 2; if (m1 > 29) h++;
- dx = 1; dy = -WORDSPERROW;
- if (h > 12) h -= 12, dx = -1, dy = WORDSPERROW;
- if (h > 6) h = 12 - h, dy = -dy;
- UpdateHand(dx,dy,&LittleHand[h][0],SetIt);
- }
-
-
- /*
- * UpdateClocks()
- *
- * Clear the clock position so the icons will remain where they are.
- * For each clock that has been openned,
- * Update the clock to the new face iamge,
- * If the clock is the one receiving NEWSCREEN reports, add its report flags.
- */
-
- static void UpdateClocks()
- {
- short i,count;
-
- ClockIcon.x = ClockIcon.y = 0;
- for (i=0, count=ClockCount; i<MAXSCREENS && count; i++)
- {
- if (Clock[i])
- {
- wUpdateIcon(Clock[i],&ClockIcon); count--;
- if (Clock[i] == NewScreenClock)
- wModifyReport(Clock[i],REPORTFLAGS | WI_REPORTNEWSCREEN);
- }
- }
- }
-
-
- /*
- * SetNewScreenClock()
- *
- * We only want one clock to report NEWSCREEN events, otherwise we would
- * be adding too many new clocks as new screens open (one for each clock
- * already open). So only the first clock in the list is marked to
- * receive NEWSCREEN message.
- *
- * Skip any blank array elements, and if we have found a clock,
- * mark it to receive NEWSCREEN messages.
- */
-
- static void SetNewScreenClock()
- {
- short i;
-
- for (i=0; i<MAXSCREENS && Clock[i] == NULL; i++);
- if (i < MAXSCREENS)
- {
- wModifyReport(Clock[i],REPORTFLAGS | WI_REPORTNEWSCREEN);
- NewScreenClock = Clock[i];
- }
- }
-
-
- /*
- * FinishClock()
- *
- * Look through the clock list for the given clock,
- * If found,
- * Clear the array element for re-use, and cancel the loop.
- * Decrement the clock count, and if this is the last one, we're done.
- * If the clock was the one receiving NEWSCREEN messages, we need to choose
- * another one to get them.
- */
-
- static int FinishClock(theClock)
- WICONREF *theClock;
- {
- short i;
- int NotDone = TRUE;
-
- for (i=0; i<MAXSCREENS; i++)
- {
- if (Clock[i] == theClock)
- {
- Clock[i] = NULL; i = MAXSCREENS;
- if (--ClockCount == 0) NotDone = FALSE; else
- if (theClock == NewScreenClock) SetNewScreenClock();
- }
- }
- return(NotDone);
- }
-
-
- /*
- * NewClock()
- *
- * If we can add more clocks,
- * Look through the clock array for an open spot.
- * If we found a spot,
- * Set the clock position: if it was specified on the command line,
- * use that, otherwise back it near the upper right.
- * Add the clock to the new screen.
- * If the add was successful, increment the clock count.
- * End the search loop.
- */
-
- static void NewClock(theScreen)
- struct Screen *theScreen;
- {
- short i;
-
- if (ClockCount < MAXSCREENS)
- {
- for (i=0; i<MAXSCREENS; i++)
- {
- if (Clock[i] == NULL)
- {
- if (ClockX || ClockY)
- {
- ClockIcon.x = ClockX;
- ClockIcon.y = ClockY;
- } else {
- ClockIcon.x = theScreen->Width - CLOCKWIDTH - 12;
- ClockIcon.y = 15;
- }
- Clock[i] = wAddIcon(theScreen,&ClockIcon);
- if (Clock[i]) ClockCount++;
- i = MAXSCREENS;
- }
- }
- }
- }
-
-
- /*
- * CreateClocks()
- *
- * Look through the Intuition screen list, and save the screen
- * pointers (we do this because we don't want te list to change while
- * we're looking at it, but we can't add icons as we go, since we
- * will enter a Wait() state which may allow other tasks to change
- * the screen list).
- * For each pointer found, try to add a clock the that screen.
- * Get a clock to receive NEWSCREEN messages.
- */
-
- static void CreateClocks()
- {
- struct Screen *Screen[MAXSCREENS];
- struct Screen *theScreen;
- short i = 0;
- int ILock;
-
- ILock = LockIBase(0L);
- theScreen = IntuitionBase->FirstScreen;
- while (theScreen)
- {
- Screen[i++] = theScreen;
- theScreen = theScreen->NextScreen;
- }
- UnlockIBase(ILock);
- while (i--) NewClock(Screen[i]);
- SetNewScreenClock();
- }
-
-
- /*
- * WaitForAction()
- *
- * Wait for the messages from the timer or the icon port.
- * While there are still clock icons on screen,
- * Get the datestamp, and recover the hours and minutes.
- * If the time has changed since the last check,
- * Remove the old hands and add the new ones.
- * Update all the clocks to use the new faces.
- * Save the time of the last update.
- * Of no timer request is pending,
- * Set up the timer request and send it.
- * Mark that a requet is pending (in case we need to remove it later).
- *
- * Wait for the timer or icon message.
- * If the timer message was returned, mark it so we can re-issue it.
- * For each icon message we receive, do the right thing:
- * OPEN: change the display format when the user double-clicks the
- * clock icon, and unselect the icon. Only change if the
- * icons is actually selected (to avoid changing during OPENALL
- * commands).
- * CLOSE: remove the icon if the user closes it.
- * AUTOREMOVE: wIconify removed the icon when it closed the screen.
- * In either casem we check to make sure it was not the NEWSCREEN
- * icon, and if so, choose another.
- * NEWSCREEN: try to open a new clock icon on the new screen.
- * Then reply to the message.
- */
-
- static void WaitForAction()
- {
- short Hours,Mins;
- short OldH = 0, OldM = 0;
- struct DateStamp theDateStamp;
- ULONG Signals;
- int NotDone = TRUE;
- struct wIconMessage *theMessage;
- extern struct wIconMessage *GetMsg();
-
- Signals = (1 << TimerPort->mp_SigBit)| (1 << ClockIcon.IconPort->mp_SigBit);
-
- while (NotDone)
- {
- DateStamp(&theDateStamp);
- Hours = theDateStamp.ds_Minute / 60;
- Mins = theDateStamp.ds_Minute % 60;
- if (Hours != OldH || Mins != OldM)
- {
- UpdateFace(OldH,OldM,FALSE);
- UpdateFace(Hours,Mins,TRUE);
- UpdateTime(ClockName,Hours,Mins);
- UpdateClocks();
- OldH = Hours; OldM = Mins;
- }
- if (TimerSet == FALSE)
- {
- TimerRequest.tr_time.tv_secs = DELAYSECS;
- TimerRequest.tr_time.tv_micro = DELAYMICS;
- SendIO(&(TimerRequest.tr_node));
- TimerSet = TRUE;
- }
-
- Wait(Signals);
- while (GetMsg(TimerPort)) TimerSet = FALSE;
- while (theMessage = GetMsg(ClockIcon.IconPort))
- {
- switch(theMessage->Action)
- {
- case WI_REPORTOPEN:
- if (wIconFlags(theMessage->Icon) & WI_SELECTED)
- {
- TimeType = (MILITARY_TIME + STANDARD_TIME) - TimeType;
- OldH = OldM = 0;
- wUnSelectIcon(theMessage->Icon);
- }
- break;
-
- case WI_REPORTCLOSE:
- wRemoveIcon(theMessage->Icon);
- case WI_REPORTAUTOREMOVE:
- NotDone = FinishClock(theMessage->Icon);
- break;
-
- case WI_REPORTNEWSCREEN:
- NewClock(theMessage->Data.Screen);
- break;
- }
- ReplyMsg(theMessage);
- }
- }
- }
-
-
- /*
- * _main()
- *
- * Replaces the standard Lattice C _main routine. It receives the
- * complete command line as a single string as its only argument.
- *
- * Parse the argument list.
- * If wIconify is active,
- * Open Intuition.
- * Set up the ports and timer stuff.
- * Create the clocks for the existing screens.
- * If there were any clocks created, wait for them to be closed,
- * Otherwise, say that none could be created.
- * Exit with no error.
- * Otherwise, say wIconify is not running.
- */
-
- void _main(line)
- char *line;
- {
- ParseArgs(line);
- if (wIconifyActive())
- {
- CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
- SetupClock();
- CreateClocks();
- if (ClockCount) WaitForAction();
- else Print("Can't create Clock Icons on any Screen\n");
- DoExit(NULL);
- } else {
- Print("wIconify not running or incompatible version\n");
- }
- }
-